package org.jeecg.modules.extbpm.process.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.GroupQuery;
import org.activiti.engine.identity.User;
import org.activiti.engine.identity.UserQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang.StreamUtils;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bpm.util.BpmUtil;
import org.jeecg.modules.extbpm.process.common.ProcDealStyleEnum;
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
import org.jeecg.modules.extbpm.process.entity.*;
import org.jeecg.modules.extbpm.process.exception.BpmException;
import org.jeecg.modules.extbpm.process.mapper.*;
import org.jeecg.modules.extbpm.process.pojo.DesignFormDataDTO;
import org.jeecg.modules.extbpm.process.pojo.RoleInfo;
import org.jeecg.modules.extbpm.process.pojo.UserInfo;
import org.jeecg.modules.extbpm.process.service.IExtActProcessService;
import org.jeecgframework.designer.util.DesUtils;
import org.jeecgframework.designer.vo.AjaxJson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.sql.Blob;
import java.sql.Clob;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 流程表
 * @author： jeecg-boot
 * @date：   2019-03-15
 * @version： V1.0
 */
@Slf4j
@Service("extActProcessService")
public class ExtActProcessServiceImpl extends ServiceImpl<ExtActProcessMapper, ExtActProcess> implements IExtActProcessService {

	@Autowired
	private ExtActProcessMapper extActProcessMapper;
	@Autowired
	private ExtActProcessFormMapper extActProcessFormMapper;
	@Autowired
	protected RepositoryService repositoryService;
	@Autowired
	private ExtActProcessNodeMapper extActProcessNodeMapper;
	@Autowired
	private ExtActProcessNodeDeploymentMapper extActProcessNodeDeploymentMapper;
	@Autowired
	private IdentityService identityService;
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private ExtActFlowDataMapper extActFlowDataMapper;
	@Autowired
	private ExtActDesignFlowDataMapper extActDesignFlowDataMapper;
	@Autowired
	private ISysBaseAPI sysBaseAPI;
	@Autowired
	@Lazy
	private RedisUtil redisUtil;

	@Override
	public List<UserInfo> getBpmUsers() {
		return extActProcessMapper.getBpmUsers();
	}

	@Override
	public Page<UserInfo> getPageBpmUsers(String account, String name, Page<UserInfo> page) {
		return page.setRecords(this.extActProcessMapper.getPageBpmUsers(page,account,name));
	}

	@Override
	public List<RoleInfo> getBpmRoles() {
		return extActProcessMapper.getBpmRoles();
	}

	@Override
	@Transactional(rollbackFor=Exception.class)
	public void deployProcess(ExtActProcess extActProcess) throws Exception {
		Deployment deployment = repositoryService.createDeployment().addInputStream(extActProcess.getProcessKey() + ".bpmn", StreamUtils.byteTOInputStream(extActProcess.getProcessXml())).name(extActProcess.getProcessKey()).deploy();
		extActProcess.setProcessStatus(WorkFlowGlobals.Process_Deploy_YES);
		//根据流程id查询流程节点,保存节点发布版本
		LambdaQueryWrapper<ExtActProcessNode> queryWrapper = new LambdaQueryWrapper<ExtActProcessNode>();
		queryWrapper.eq(ExtActProcessNode::getProcessId, extActProcess.getId());
		List<ExtActProcessNode> nodelist = extActProcessNodeMapper.selectList(queryWrapper);
		if(nodelist!=null&&nodelist.size()>0){
			for(ExtActProcessNode node:nodelist){
				ExtActProcessNodeDeployment processnodeDeployment = new ExtActProcessNodeDeployment();
				processnodeDeployment.setDeploymentId(deployment.getId());
				processnodeDeployment.setFormId(node.getFormId());
				processnodeDeployment.setModelAndView(node.getModelAndView());
				processnodeDeployment.setModelAndViewMobile(node.getModelAndViewMobile());
				processnodeDeployment.setNodeTimeout(node.getNodeTimeout());
				processnodeDeployment.setProcessId(node.getProcessId());
				processnodeDeployment.setProcessNodeCode(node.getProcessNodeCode());
				processnodeDeployment.setProcessNodeName(node.getProcessNodeName());
				extActProcessNodeDeploymentMapper.insert(processnodeDeployment);
			}
		}
		extActProcessMapper.updateById(extActProcess);
	}

	@Override
	public void cleanBpmUser() {
		extActProcessMapper.cleanBpmActIdMembership();
		extActProcessMapper.cleanBpmActIdUser();
		extActProcessMapper.cleanBpmActIdGroup();
	}

	@Override
	public List<UserInfo> getSysUsers() {
		return extActProcessMapper.getSysUsers();
	}

	@Override
	public List<RoleInfo> getSysRolesByUserId(String userId) {
		return extActProcessMapper.getSysRolesByUserId(userId);
	}

	@Override
	public void saveActIdMembership(UserInfo user, List<RoleInfo> roleList) {
		UserQuery userQuery = identityService.createUserQuery();
		List<User> activitiUsers = userQuery.userId(user.getId()).list();
		User actUser = null;
		if (activitiUsers.size() == 1) {
			actUser = activitiUsers.get(0);
		} else if (activitiUsers.size() > 1) {
			String errorMsg = "发现重复用户：id=" + user.getId();
			throw new RuntimeException(errorMsg);
		} else {
			actUser = identityService.newUser(user.getId());
		}
		//保存和更新用户
		saveOrUpdataActUser(user,actUser);
		//保存和更新用户组
		saveOrUpdataActGroup(roleList);
		//更新用户和组的关系
		savaMembership(user, roleList);
	}
	
	
	private void saveOrUpdataActUser(UserInfo user, User actUser) {
		actUser.setFirstName(user.getFirstName());
		actUser.setLastName(user.getFirstName());
		actUser.setEmail(user.getEmail());
		identityService.saveUser(actUser);
	}
	
	private void saveOrUpdataActGroup(List<RoleInfo> roleList) {
		GroupQuery groupQuery = identityService.createGroupQuery();
		for(RoleInfo role:roleList) {
			List<Group> activitiGroups = groupQuery.groupId(role.getId()).list();
			if (activitiGroups.size() <= 0) {
				Group activitiGroup = identityService.newGroup(role.getId());
				activitiGroup.setId(role.getId());
				activitiGroup.setName(role.getName());
				identityService.saveGroup(activitiGroup);
			}
		}
	}

	private void savaMembership(UserInfo user, List<RoleInfo> roleList) {
		// 删除用户的组关系
		List<Group> activitiGroups = identityService.createGroupQuery().groupMember(user.getId()).list();
		for (Group group : activitiGroups) {
			log.debug("delete group from activit: {}", group);
			identityService.deleteMembership(user.getId(), group.getId());
		}
		//添加用户的组关系
		for(RoleInfo role:roleList) {
			identityService.createMembership(user.getId(), role.getId());
		}
	}

	@Override
	public Map<String, Object> getDataById(String tableName, String id) {
		Map<String, Object> result = new HashMap<>();
		Map<String, Object> data = extActProcessMapper.getDataById(tableName, id);
		for (Map.Entry<String, Object> entry : data.entrySet()) {
			//update-begin--- author:scott---date:20201227------for:JT-250【流程】特殊字段 发起流程失败------
			//大字段处理
			if(entry.getValue()!=null && (entry.getValue() instanceof Clob || entry.getValue() instanceof Blob)){
				continue;
			}
			//update-end--- author:scott---date:20201227------for:JT-250【流程】特殊字段 发起流程失败------
			result.put(entry.getKey().toLowerCase(),entry.getValue());
		}
		return result;
	}

	/**
	 * 流程提交接口（online，自定义开发）
	 * @param userid
	 * @param dataId
	 * @param dataForm
	 * @param extActProcessForm
	 * @return
	 * @throws BpmException
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public ProcessInstance startMutilProcess(String userid, String dataId, Map<String, Object> dataForm,
			ExtActProcessForm extActProcessForm) throws BpmException {
		ExtActFlowData extActFlowData = new ExtActFlowData();
		extActFlowData.setBpmStatusField(extActProcessForm.getFlowStatusCol());
		extActFlowData.setFormDataId(dataId);
		extActFlowData.setFormTableName(extActProcessForm.getFormTableName());
		extActFlowData.setProcessFormId(extActProcessForm.getId());
		extActFlowData.setRelationCode(extActProcessForm.getRelationCode());
		extActFlowData.setUserId(userid);
		//启动流程
		dataForm.put(WorkFlowGlobals.BPM_STATUS,WorkFlowGlobals.BPM_BUS_STATUS_2);
		ProcessInstance processInstance = this.startWorkflow(userid, dataId, dataForm, extActProcessForm);
		extActFlowData.setProcessKey(processInstance.getProcessDefinitionKey());
		extActFlowData.setProcessInstId(processInstance.getProcessInstanceId());
		//update-begin--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------
		extActFlowData.setBpmStatus(WorkFlowGlobals.BPM_BUS_STATUS_2);
		extActFlowData.setProcessName(processInstance.getProcessDefinitionName());
		extActFlowData.setProcessExpTitle(extActProcessForm.getTitleExp());
		extActFlowData.setFormType(extActProcessForm.getFormType());

		//通过datad,process_key，relationCode查询数据是否存在
		LambdaQueryWrapper<ExtActFlowData> queryWrapper = new LambdaQueryWrapper<ExtActFlowData>();
		queryWrapper.eq(ExtActFlowData::getBpmStatusField, extActProcessForm.getFlowStatusCol());
		queryWrapper.eq(ExtActFlowData::getFormDataId, dataId);
		queryWrapper.eq(ExtActFlowData::getFormTableName, extActProcessForm.getFormTableName());
		queryWrapper.eq(ExtActFlowData::getProcessFormId, extActProcessForm.getId());
		queryWrapper.eq(ExtActFlowData::getRelationCode, extActProcessForm.getRelationCode());
		queryWrapper.eq(ExtActFlowData::getUserId, userid);
		queryWrapper.eq(ExtActFlowData::getProcessKey, processInstance.getProcessDefinitionKey());
		queryWrapper.isNull(ExtActFlowData::getProcessInstId);
		ExtActFlowData t = extActFlowDataMapper.selectOne(queryWrapper);
		if (t != null) {
            extActFlowData.setId(t.getId());
			extActFlowDataMapper.updateById(extActFlowData);
		} else {
			//保存
			extActFlowDataMapper.insert(extActFlowData);
		}
		//update-end--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------

		//更新表单状态
		String tableName = extActProcessForm.getFormTableName().toUpperCase();
		String col = extActProcessForm.getFlowStatusCol().toUpperCase();
		if(oConvertUtils.isEmpty(col)) {
			col = "BPM_STATUS";
		}
		//回写业务数据的流程状态
		extActProcessMapper.updateBpmStatusById(tableName, dataId, col, WorkFlowGlobals.BPM_BUS_STATUS_2);
		return processInstance;
	}

	/**
	 * online表单/自定义开发表单 流程启动
	 * @param username 流程发起人账号
	 * @param flowCode 流程关联编码
	 * @param id  表单业务数据id
	 * @param formUrl  流程表单URL
	 * @param formUrlMobile 流程表单移动URL
	 * @throws BpmException
	 */
	@Override
	public ProcessInstance startMutilProcessApi(String username,String flowCode, String id, String formUrl,String formUrlMobile) throws BpmException {
		if(oConvertUtils.isEmpty(flowCode)) {
			throw new BpmException("flowCode参数不能为空");
		}
		if(oConvertUtils.isEmpty(id)) {
			throw new BpmException("id参数不能为空");
		}
		if(oConvertUtils.isEmpty(formUrl)) {
			throw new BpmException("formUrl参数不能为空");
		}
		if(oConvertUtils.isEmpty(username)) {
			throw new BpmException("流程发起人，参数不能为空");
		}
		ExtActProcessForm extActProcessForm = null;
		Map<String, Object> dataForm = new HashMap<String, Object>();
		try {
			//查询流程业务关联配置
			LambdaQueryWrapper<ExtActProcessForm> queryWrapper = new LambdaQueryWrapper<ExtActProcessForm>();
			queryWrapper.eq(ExtActProcessForm::getRelationCode, flowCode);
			extActProcessForm = extActProcessFormMapper.selectOne(queryWrapper);
			//获取业务数据，并且加载到流程变量中
			String tableName = extActProcessForm.getFormTableName();
			dataForm = this.getDataById(tableName, id);
			dataForm.put(WorkFlowGlobals.BPM_DATA_ID, id);
			dataForm.put(WorkFlowGlobals.BPM_FORM_CONTENT_URL, formUrl);
			if(oConvertUtils.isNotEmpty(formUrlMobile)){
				dataForm.put(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE, formUrlMobile);
			}else{
				//没有传移动端表单，默认用PC端
				dataForm.put(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE, formUrl);
			}
			dataForm.put(WorkFlowGlobals.BPM_FORM_KEY, tableName);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BpmException("获取流程信息异常");
		}
		ProcessInstance processInstance = this.startMutilProcess(username, id, dataForm, extActProcessForm);
		log.info("启动成功流程实例 ProcessInstance: ",processInstance);
		return processInstance;
	}

	//update-begin--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------
	/**
	 * 保存流程表单草稿箱（online，自定义开发）
	 * @param userid
	 * @param dataId
	 * @param dataForm
	 * @param extActProcessForm
	 * @return
	 * @throws BpmException
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public ExtActFlowData saveMutilProcessDraft(String userid, String dataId,ExtActProcessForm extActProcessForm) throws BpmException {
		ExtActFlowData extActFlowData = new ExtActFlowData();
		extActFlowData.setBpmStatusField(extActProcessForm.getFlowStatusCol());
		extActFlowData.setFormDataId(dataId);
		//如果是表单设计器单据对接流程，则关联表写死 “EXT_ACT_DESIGN_FLOW_DATA”
		if (extActProcessForm.getRelationCode().indexOf("desform_") != -1) {
			extActFlowData.setFormTableName(WorkFlowGlobals.DESIGN_FORM_DRAFT_TABLE);
		} else {
			extActFlowData.setFormTableName(extActProcessForm.getFormTableName());
		}
		extActFlowData.setProcessFormId(extActProcessForm.getId());
		extActFlowData.setRelationCode(extActProcessForm.getRelationCode());
        extActFlowData.setBpmStatus(WorkFlowGlobals.BPM_BUS_STATUS_1);
		//根据流程id查询流程信息
		ExtActProcess extActProcess = extActProcessMapper.selectById(extActProcessForm.getProcessId());
		extActFlowData.setProcessKey(extActProcess.getProcessKey());
		extActFlowData.setUserId(userid);
		extActFlowData.setProcessName(extActProcess.getProcessName());
		extActFlowData.setProcessExpTitle(extActProcessForm.getTitleExp());
		extActFlowData.setFormType(extActProcessForm.getFormType());

		//保存
		extActFlowDataMapper.insert(extActFlowData);
		return extActFlowData;
	}
    //update-end--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------

	/**
	 * 表单设计器的表单发起流程
	 * @param userid
	 * @param dataId
	 * @param dataForm
	 * @param extActProcessForm
	 * @throws BpmException
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public void startDesFormMutilProcess(String userid, String dataId, Map<String, Object> dataForm,
			ExtActProcessForm extActProcessForm) throws BpmException {
		String tableName = (String)dataForm.get(WorkFlowGlobals.BPM_FORM_KEY);
		ExtActFlowData extActFlowData = new ExtActFlowData();
		extActFlowData.setBpmStatusField(extActProcessForm.getFlowStatusCol());
		extActFlowData.setFormDataId(dataId);
		extActFlowData.setFormTableName(tableName);
		extActFlowData.setProcessFormId(extActProcessForm.getId());
		extActFlowData.setRelationCode(extActProcessForm.getRelationCode());
		extActFlowData.setUserId(userid);
		//查询自定义表单流程中心数据
        log.debug("-- startDesFormMutilProcess --- dataId： "+ dataId);
		LambdaQueryWrapper<ExtActDesignFlowData> queryWrapperDesData = new LambdaQueryWrapper<ExtActDesignFlowData>();
		queryWrapperDesData.eq(ExtActDesignFlowData::getId, dataId);
		ExtActDesignFlowData extActDesignFlowData = extActDesignFlowDataMapper.selectOne(queryWrapperDesData);
		log.debug("-- startDesFormMutilProcess --- extActDesignFlowData： "+ extActDesignFlowData);
		dataForm.put(WorkFlowGlobals.BPM_DES_DATA_ID, extActDesignFlowData.getDesformDataId());
		dataForm.put(WorkFlowGlobals.BPM_DES_FORM_CODE, extActDesignFlowData.getDesformCode());
		dataForm.put(WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.BPM_BUS_STATUS_2);
		//启动流程
		ProcessInstance processInstance = this.startWorkflow(userid, dataId, dataForm, extActProcessForm);
		extActFlowData.setProcessKey(processInstance.getProcessDefinitionKey());
		extActFlowData.setProcessInstId(processInstance.getProcessInstanceId());
		//update-begin--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------
		extActFlowData.setBpmStatus(WorkFlowGlobals.BPM_BUS_STATUS_2);
		extActFlowData.setProcessName(processInstance.getProcessDefinitionName());
		extActFlowData.setProcessExpTitle(extActProcessForm.getTitleExp());
		extActFlowData.setFormType(extActProcessForm.getFormType());

		//通过datad,process_key，relationCode查询数据是否存在
		LambdaQueryWrapper<ExtActFlowData> queryWrapper = new LambdaQueryWrapper<ExtActFlowData>();
		queryWrapper.eq(ExtActFlowData::getBpmStatusField, extActProcessForm.getFlowStatusCol());
		queryWrapper.eq(ExtActFlowData::getFormDataId, dataId);
		queryWrapper.eq(ExtActFlowData::getFormTableName, tableName);
		queryWrapper.eq(ExtActFlowData::getProcessFormId, extActProcessForm.getId());
		queryWrapper.eq(ExtActFlowData::getRelationCode, extActProcessForm.getRelationCode());
		queryWrapper.eq(ExtActFlowData::getUserId, userid);
		queryWrapper.eq(ExtActFlowData::getProcessKey, processInstance.getProcessDefinitionKey());
		queryWrapper.isNull(ExtActFlowData::getProcessInstId);
		ExtActFlowData t = extActFlowDataMapper.selectOne(queryWrapper);
		if (t != null) {
			extActFlowData.setId(t.getId());
			extActFlowDataMapper.updateById(extActFlowData);
		} else {
			//保存
			extActFlowDataMapper.insert(extActFlowData);
		}
        //update-begin--- author:scott---date:20200313------for:移动OA统一草稿箱功能（online表单+设计器表单）,在保存表单时，判断关联流程的话则往流程中间表插入表单数据------------

		//update-begin--Author:scott  Date:20191121 for：表单设计器表单 流程发起后，未回写物理表的流程状态
		//更新物理表流程状态
		String desFormCode = oConvertUtils.getString(dataForm.get(WorkFlowGlobals.BPM_DES_FORM_CODE));
		String bpmDesDataId = oConvertUtils.getString(dataForm.get(WorkFlowGlobals.BPM_DES_DATA_ID));
		log.debug("------------------【表单设计器】回写物理表的流程状态------------------");
		String dbTableName = extActDesignFlowDataMapper.getDesignFormRelationTableName(desFormCode);
		log.debug("--------【表单设计器】回写物理表的流程状态-------- desFormCode： "+ desFormCode);
		log.debug("--------【表单设计器】回写物理表的流程状态-------- bpmDesDataId： "+ bpmDesDataId);
		log.debug("--------【表单设计器】回写物理表的流程状态-------- dbTableName： "+ dbTableName);
		DesignFormDataDTO designFormDataDto = extActDesignFlowDataMapper.getDesignFormDataById(bpmDesDataId);
		log.debug("--------【表单设计器】回写物理表的流程状态-------- designFormDataDto： "+ designFormDataDto);
		//通过表单设计编码，找对关联的物理表
		if(oConvertUtils.isNotEmpty(dbTableName) && designFormDataDto!=null && oConvertUtils.isNotEmpty(designFormDataDto.getOnlineFormDataId())){
			String col = extActProcessForm.getFlowStatusCol().toUpperCase();
			if(oConvertUtils.isEmpty(col)) {
				col = "BPM_STATUS";
			}
			log.debug("--------【表单设计器】回写物理表的流程状态-------- update column： "+ col);
			log.debug("--------【表单设计器】回写物理表的流程状态-------- getOnlineFormDataId： "+ designFormDataDto.getOnlineFormDataId());
			extActProcessMapper.updateBpmStatusById(dbTableName, designFormDataDto.getOnlineFormDataId(), col, WorkFlowGlobals.BPM_BUS_STATUS_2);
		}
		//update-end--Author:scott  Date:20191121 for：表单设计器表单 流程发起后，未回写物理表的流程状态

		//TODO 更新自定义单据数据中心表信息
		extActDesignFlowData.setBpmStatus(WorkFlowGlobals.BPM_BUS_STATUS_2);
		extActDesignFlowData.setFlowCode(extActProcessForm.getRelationCode());
		//extActDesignFlowData.setProcessName(processInstance.getName());
		//String bpmTitle = (String)dataForm.get(WorkFlowGlobals.BPM_BIZ_TITLE);
		//extActDesignFlowData.setBpmTitle(bpmTitle);
		extActDesignFlowDataMapper.updateById(extActDesignFlowData);
	}
	
	/**
	 * 启动流程
	 * @throws BusinessException 
	 */
	private ProcessInstance startWorkflow(String userid, String businessKey, Map<String, Object> variables, ExtActProcessForm extActProcessForm) throws BpmException{
		identityService.setAuthenticatedUserId(userid);// 设置流程发起人
		variables.put(WorkFlowGlobals.BPM_FORM_BUSINESSKEY, businessKey);
		variables.put(WorkFlowGlobals.BPM_FORM_TYPE, extActProcessForm.getFormType());
		variables.put(WorkFlowGlobals.BPM_BIZ_TITLE, BpmUtil.getContent(variables,extActProcessForm.getTitleExp()));
		variables.put(WorkFlowGlobals.BPM_PROC_DEAL_STYLE, ProcDealStyleEnum.toEnum(extActProcessForm.getFormDealStyle()).getCode());
		//根据流程id查询流程信息
		ExtActProcess extActProcess = extActProcessMapper.selectById(extActProcessForm.getProcessId());
		//获取最新发布的流程定义
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(extActProcess.getProcessKey()).latestVersion().singleResult();
		//update-begin--Author:zhoujf  Date:20180727 for：流程未发布流程提交异常处理
		if(processDefinition==null){
			throw new BpmException("流程未发布，请先发布流程！");
		}
		String formUrl = (String)variables.get(WorkFlowGlobals.BPM_FORM_CONTENT_URL);
		String formUrlM = (String)variables.get(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE);
		formUrl = BpmUtil.getNodeUrl(variables, formUrl, businessKey);
		formUrlM = BpmUtil.getNodeUrl(variables, formUrlM, businessKey);
		variables.put(WorkFlowGlobals.BPM_FORM_CONTENT_URL, formUrl);
		variables.put(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE, formUrlM);
		
		//根据流程id和部署id查询流程部署节点
//		List<ExtActProcessNodeDeployment> nodeList = new ArrayList<ExtActProcessNodeDeployment>();
//		LambdaQueryWrapper<ExtActProcessNodeDeployment> queryWrapper = new LambdaQueryWrapper<ExtActProcessNodeDeployment>();
//		queryWrapper.eq(ExtActProcessNodeDeployment::getProcessId, extActProcessForm.getProcessId());
//		queryWrapper.eq(ExtActProcessNodeDeployment::getDeploymentId, processDefinition.getDeploymentId());
//		nodeList = extActProcessNodeDeploymentService.list(queryWrapper);
//		if(nodeList!=null&&nodeList.size()>0){
//			for(ExtActProcessNodeDeployment node:nodeList){
//				if(oConvertUtils.isNotEmpty(node.getModelAndView())){
//					variables.put(node.getProcessNodeCode()+":"+WorkFlowGlobals.SUFFIX_BPM_FORM_URL, node.getModelAndView());
//				}
//				if(oConvertUtils.isNotEmpty(node.getModelAndViewMobile())){
//					variables.put(node.getProcessNodeCode()+":"+WorkFlowGlobals.SUFFIX_BPM_FORM_URL_MOBILE, node.getModelAndViewMobile());
//				}
//			}
//		}
		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(extActProcess.getProcessKey(), businessKey, variables);
		if(processInstance==null||oConvertUtils.isEmpty(processInstance.getProcessInstanceId())){
			return null;
		}
		//将流程实例ID存在流程变量里面
		runtimeService.setVariable(processInstance.getProcessInstanceId(), WorkFlowGlobals.JG_LOCAL_PROCESS_ID, processInstance.getProcessInstanceId());
		return processInstance;
	}

	@Override
	public void deleteActIdMembership(String userName) {
		identityService.deleteUser(userName);
		
	}

	@Override
	public List<String> getProcessKeysByProcessName(String processName) {
		return extActProcessMapper.getProcessKeysByProcessName(processName);
	}

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxJson saveProcess(HttpServletRequest request) throws Exception {
        AjaxJson j = new AjaxJson();
        String processDefinitionId = oConvertUtils.getString(request.getParameter("processDefinitionId"));
        String processDescriptor = oConvertUtils.getString(request.getParameter("processDescriptor"));
        String processName = oConvertUtils.getString(request.getParameter("processName"));
        String processkey = oConvertUtils.getString(request.getParameter("processkey"));// 流程ID
        String params = oConvertUtils.getString(request.getParameter("params"));
        String nodes = oConvertUtils.getString(request.getParameter("nodes"));// 流程节点
        String typeid = oConvertUtils.getString(request.getParameter("typeid"));// 流程类型
        String token = oConvertUtils.getString(request.getParameter("token"));

        log.info(" saveProcess 登录令牌token： " + token);
        //校验 token 登录有效性
        TokenUtils.verifyToken(request, sysBaseAPI, redisUtil);

        DesUtils.checkNodeDuplicate(nodes);
        log.info(" processDefinitionId ：" + processDefinitionId);
        log.info(" processDescriptor ：" + processDescriptor);

        ExtActProcess process = extActProcessMapper.selectById(processDefinitionId);
        //第一次进入设计流程的时候，processDefinitionId始终为零，导致流程保存多份
        if ("0".equals(processDefinitionId) && process == null) {
            LambdaQueryWrapper<ExtActProcess> queryWrapper = new LambdaQueryWrapper<ExtActProcess>();
            queryWrapper.eq(ExtActProcess::getProcessKey, processkey);
            process = extActProcessMapper.selectOne(queryWrapper);
        }
        if (process != null) {
            process.setProcessName(processName);
            process.setProcessKey(processkey);

			//--------------------------------------------------------------------------------
			//判断流程processkey是否存在重复
			LambdaQueryWrapper<ExtActProcess> queryWrapper = new LambdaQueryWrapper<ExtActProcess>();
			queryWrapper.eq(ExtActProcess::getProcessKey, processkey);
			ExtActProcess dbProcess = extActProcessMapper.selectOne(queryWrapper);
			if(dbProcess!=null && !"0".equals(processDefinitionId) && oConvertUtils.isNotEmpty(processDefinitionId) && !processDefinitionId.equals(dbProcess.getId())){
				j.setMsg("保存流程失败，流程ID重复！");
				j.setSuccess(false);
				return j;
			}
			//--------------------------------------------------------------------------------

            if (StringUtils.isNotEmpty(typeid)) {
                process.setProcessType(typeid);
            }
            process.setProcessXml(StreamUtils.StringTObyte(processDescriptor));
            extActProcessMapper.updateById(process);
            j.setMsg("流程修改成功");
        } else {
            process = new ExtActProcess();
            process.setProcessName(processName);
            process.setProcessKey(processkey);
            if (StringUtils.isNotEmpty(typeid)) {
                process.setProcessType(typeid);
            }
            process.setProcessXml(StreamUtils.StringTObyte(processDescriptor));
            process.setProcessStatus(WorkFlowGlobals.Process_Deploy_NO);
            extActProcessMapper.insert(process);
            j.setMsg("流程创建成功");
            j.setObj(process.getId());
        }

        //同步修改流程节点配置
        if (nodes != null && nodes.length() > 3) {
            String[] temp = nodes.split("@@@");
            for (int i = 0; i < temp.length; i++) {
                ExtActProcessNode processnode = null;
                String[] fileds = temp[i].split("###");
                String tid = fileds[0].substring(3);
                String name = fileds[1].substring(9);
                processnode = extActProcessNodeMapper.queryByNodeCodeAndProcessKey(processkey, tid);
                if (processnode == null) {
                    processnode = new ExtActProcessNode();
                    processnode.setProcessNodeCode(tid);
                    processnode.setProcessNodeName(name);
                    processnode.setProcessId(process.getId());
                    extActProcessNodeMapper.insert(processnode);
                } else {
                    processnode.setProcessNodeCode(tid);
                    processnode.setProcessNodeName(name);
                    processnode.setProcessId(process.getId());
                    extActProcessNodeMapper.updateById(processnode);
                }
            }
        }
        return j;
    }
}
